﻿using System;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using MetaSharp.Transformation.Patterns;

namespace MetaSharp.Transformation
{
	public sealed class MemoKey : IEquatable<MemoKey>, IComparable<MemoKey>
	{
		private readonly IStream _stream;
        private readonly RulePattern origin;
		private long hash;

        public IStream Stream
        {
            get { return _stream; }
        }

		public MemoKey(IStream stream, RulePattern origin)
		{
			if (stream == null)
				throw new ArgumentNullException("stream");
            if (origin == null)
                throw new ArgumentNullException("origin");

			this._stream = stream;
            this.origin = origin;

            var m = (long)origin.GetHashCode();
            var p = (long)stream.GetHashCode();
            this.hash = m ^ p;
		}

		public bool Equals(MemoKey other)
		{
            return this.CompareTo(other) == 0;
		}

		public override int GetHashCode()
		{
			return (int)this.hash;
		}

		public override bool Equals(object obj)
		{
			var memoKey = obj as MemoKey;
			if (memoKey == null)
				return false;

			return Equals(memoKey);
		}

		public int CompareTo(MemoKey other)
		{
			if (other == null)
				return 1;

            var i = this.Stream.CompareTo(other.Stream);
            if (i == 0)
            {
                if (object.ReferenceEquals(this.origin, other.origin))
                    return 0;

                return this.hash.CompareTo(other.hash);
            }

            return i;
        }

		public static bool operator ==(MemoKey a, MemoKey b)
		{
			if (ReferenceEquals(a, null) != ReferenceEquals(b, null))
				return false;

			return ReferenceEquals(a, null) || a.Equals(b);
		}

		public static bool operator !=(MemoKey a, MemoKey b)
		{
			return !(a == b);
		}

        public override string ToString()
        {
            return string.Format(
                CultureInfo.InvariantCulture,
                "MemoKey {{ Index={0], Pattern={1}, Hash={2} }}",
                this.Stream.Index,
                this.origin,
                this.hash);
        }
	}
}
